"""
1. 集合（set）元素去重的判断依据是什么

集合元素的去重是基于元素的哈希值来判断的。
具体来说，集合中的每个元素都必须是可哈希的（即不可变类型），这样Python才能为每个元素计算出一个唯一的哈希值。
当你将一个元素添加到集合中时，Python会首先计算该元素的哈希值，然后检查集合中是否已经存在具有相同哈希值的元素。
如果存在相同哈希值的元素，Python会进行进一步的比较来确定是否是相同的元素。
如果元素的哈希值相同且比较结果为相等，Python会认为这两个元素是相同的，因此集合中不会出现重复的元素。
"""
import json

"""
2. 总结本周视频讲解魔术方法的作用及什么情况会执行到该方法
__new__  实例化对象时调用
__init__  实例化之后首先执行的方法
__str__  str()函数、format()函数、print()函数调用，需要返回对象的字符串表达时执行
__repr__  与__str__魔术方法类似，有__str__会调用__str__，没有就调用__repr__方法
__bytes__  bytes()函数调用，返回一个对象的bytes表达
__hash__   内建函数调用hash()的时候调用
__eq__     使用==的时候会调用
__bool__   内建函数bool()，或者对象放在逻辑表达式的位置，调用这个函数
__lt__,__le__, __eq__, __gt__, __ge__,__ne__  用到比较运算符的时候会调用
__add__, __sub__, __mul__, __truediv__, __mod__, __floordiv__, __pow__, __divmod__ 算数运算符，移位、位运算也有对应的方法
__iadd__, __isub__, __imul__, __itruediv__, __imod__, __ifloordiv__, __ipow__   用于实现原地操作，原地操作是指在不创建新对象的情况下，直接修改对象的值。这些方法通常与赋值运算符（如 +=、-=、*=等）一起使用，以实现对对象进行原地操作
__len__    用到len()的时候会调用，返回对象长度
__iter__    需要迭代的时候，加上这个魔术方法
__contains__  in运算符的时候调用
__getitem__   索引的魔术方法
__setitem__   赋值的魔术方法
__missing__   字典中键缺失时的行为相关的特殊方法
__call__      类中定义一个该方法，实例就可以像函数一样调用
__enter__      进入上下文的时候调用
__exit__       退出上下文的时候调用
"""

"""
3. 结合本周所学内容，实现如下类：
   class Ob:
     pass
   
   执行以下操作：
   a = Ob('tom')
   b = Ob('tom')
   print('a: ', a)
   a[0] = 'a'
   print('a:', a)
   a * 3
   print('len: ', len(a))
   del a[1]
   print('a: ', a)
   print('set: ', {a, b})
   
   其输出如下：
   a: ['1', '2']
   a: ['a', '2']
   len:  6
   a: ['a', 'a', '2', 'a', '2']
   set: {<Ob name=tom items=['a', 'a', '2', 'a', '2']>}
"""


class Ob:
    def __init__(self, name):
        self.name = name
        self.items = ["1", "2"]

    def __str__(self):
        return json.dumps(self.items)

    def __getitem__(self, item):
        return self.items[item]

    def __setitem__(self, key, value):
        self.items[key] = value
        return self

    def __mul__(self, other):
        self.items *= other

    def __len__(self):
        return len(self.items)

    def __delitem__(self, key):
        del self.items[key]

    def __repr__(self):
        return "<Ob name={} items={}>".format(self.name, self.items)


a = Ob('tom')
b = Ob('tom')
print('a: ', a)  # a: ['1', '2']
a[0] = 'a'
print('a:', a)  # a: ['a', '2']
a * 3
print('len: ', len(a))  # len:  6
del a[1]
print('a: ', a)  # a: ['a', 'a', '2', 'a', '2']
print('set: ', {a, b})  # set: {<Ob name=tom items=['a', 'a', '2', 'a', '2']>}
